package com.gitee.cui.basic.cas;

import com.gitee.cui.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 原子类测试
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/11/22 14:26
 **/
@Slf4j
public class AtomicTest {

    private static final int THREAD_COUNT = 10;

    @Test
    public void atomicIntegerTest() {
        int tempValue = 0;
        AtomicInteger i = new AtomicInteger(0);
        tempValue = i.getAndSet(3);
        log.info("tempValue: {}；i: {}", tempValue, i.get());

        tempValue = i.getAndIncrement();
        log.info("tempValue: {}；i: {}", tempValue, i.get());

        tempValue = i.getAndAdd(5);
        log.info("tempValue: {}；i: {}", tempValue, i.get());

        boolean flag = i.compareAndSet(9, 100);
        log.info("flag:{};i:{}", flag, i.get());
    }

    @Test
    public void atomicStampedReferenceTest() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(2);

        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1, 0);

        ThreadUtil.getMixedTargetThreadPool().submit(() ->{
            boolean success = false;
            int stamp = atomicStampedReference.getStamp();
            log.info("before sleep 500: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());
            ThreadUtil.sleepMilliSeconds(500);
            success = atomicStampedReference.compareAndSet(1, 10, stamp, stamp + 1);
            log.info("after sleep 500 cas 1: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());

            stamp++;

            success = atomicStampedReference.compareAndSet(10, 1, stamp, stamp + 1);
            log.info("after sleep 500 cas 2: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());
            latch.countDown();
        });

        ThreadUtil.getMixedTargetThreadPool().submit(() ->{
            boolean success = false;
            int stamp = atomicStampedReference.getStamp();
            log.info("before sleep 1000: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());
            ThreadUtil.sleepMilliSeconds(1000);
            log.info("after sleep 1000: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());
            success = atomicStampedReference.compareAndSet(1, 20, stamp, stamp + 1);
            log.info("after sleep 1000 cas 3: value={}, stamp={}", atomicStampedReference.getReference(), atomicStampedReference.getStamp());

            latch.countDown();
        });
        latch.wait();
    }
}
